<template>
	<view>
		<view id="webgl" class="webgl-content"></view>
		<!-- <canvas type="webgl" id="webgl" class="webgl-content"></canvas> -->
		<view class="progress" v-if="isLoading">
			<view class="progress-full" :style="`width:${progress}%;`"></view>
		</view>
	</view>
</template>

<script module="three" lang="renderjs">
	import { createScopedThreejs } from 'threejs-miniprogram';
	import { GLTFLoader } from '@/common/three/examples/jsm/loaders/GLTFLoader.js';
	// import { registerGLTFLoader  } from '@/common/threejs-miniprogram/loaders/gltf-loader';
	import { OrbitControls } from '@/common/three/examples/jsm/controls/OrbitControls.js';
	import { RoomEnvironment } from '@/common/three/examples/jsm/environments/RoomEnvironment.js';
	import { GUI } from '@/common/three/examples/jsm/libs/lil-gui.module.min.js';
	
	import Stats from '@/common/three/examples/jsm/libs/stats.module.js'; //引入性能监视器stats.js

	const THREE = require('@/common/three/build/three.module.js')

	export default {
		name: "",
		data() {
			return {
				isLoading: false,
				progress: 0,
				camera: null,
				scene: null,
				renderer: null,
				controls: null,
				theObject: null,
				gui: null,
				stats: null,
				gltfList: [
					'fan.glb',
				],
				wheels: [],
				heightList: [],
				container: null,
				loaderGLTF: null
			};
		},
		mounted() {
			this.init();
			window.addEventListener('resize', this.onWindowResize);
		},
		methods: {
			init() {
				this.container = document.getElementById('webgl');
				//创建stats对象
				this.stats = new Stats();
				// 实例化一个gui对象
				this.gui = new GUI();
				this.gui.domElement.style.right = '0px';
				this.gui.domElement.style.width = '300px';

				this.container.appendChild(this.stats.domElement);
				// 场景
				this.initScene();
				// 加载模型
				this.initModel();
				// 像机
				this.initCamera();
				// 灯光
				this.initLight();
				// 渲染器
				this.initRenderer();
				// 控制
				this.initControls();
				// 动画渲染
				this.animate();

				// gui.add(model.position, 'x', 0, 100).name("X轴位移").onChange(function(value){
				// 	model.position.x = value;
				// });

				// 环境光强度
				// const lightFolder = this.gui.addFolder('光照');
				// lightFolder.add(hemiLight, 'intensity',0,2).name("半球光强度");
				// lightFolder.add(ambientLight, 'intensity',0,2).name("环境光强度");
				// lightFolder.add(light, 'intensity',0, 1).name("平行光强度");
				// lightFolder.add(pointLight, 'intensity',0, 1).name("点光强度");

				//gui.close();//关闭菜单
			},

			async initModel() {
				let model = await this.loadGLTF('./static/model/fan2.glb')
				//model.position.set( 0, 0, 0 );
				//model.scale.set( 2, 2, 2 );
				this.setCenter(model)
				model.traverse((obj) => {
					if (obj.isMesh) {
						//obj.material = obj.material.clone()
						if (obj.name.includes("圆环")) {
							//obj.material = new THREE.MeshLambertMaterial({ color:0xffffff, });
							obj.material = new THREE.MeshPhysicalMaterial({
								color: 0x00ffff,
								metalness: 0.9, //金属度
								roughness: 0.5, //粗糙度
								clearcoat: 1.0, //物体表面清漆层或者说透明涂层的厚度
								clearcoatRoughness: 0.1, //透明涂层表面的粗糙度
								transmission: 1.0, //玻璃材质透光率，
								ior: 1.5, //折射率
							});
						}

						// 初始化调试菜单
						this.initModelMenu(obj)
						//console.log("默认材质：",obj.material)
					}
				})
				this.scene.add(model);
			},

			initScene() {
				// 创建场景
				this.scene = new THREE.Scene();
				this.scene.background = new THREE.Color(0xbbbbbb); //背景色
				// 添加辅助网格
				const grid = new THREE.GridHelper(100, 20, 0xffffff, 0xffffff);
				grid.material.opacity = 0.2;
				grid.material.depthWrite = false;
				grid.material.transparent = true;
				this.scene.add(grid);
				// 添加辅助坐标系
				const axesHelper = new THREE.AxesHelper(100);
				this.scene.add(axesHelper);
			},

			initRenderer() {
				const width = this.container.clientWidth; //窗口宽度
				const height = this.container.clientHeight; //窗口高度
				this.renderer = new THREE.WebGLRenderer();
				this.renderer.setSize(width, height); //设置渲染区域尺寸
				this.renderer.outputEncoding = THREE.sRGBEncoding;
				//renderer.setClearColor(0xb9d3ff, 0.4); // 设置背景颜色透明度
				this.renderer.setPixelRatio(window.devicePixelRatio); //设置的设备像素比
				// 添加环境效果
				const environment = new RoomEnvironment();
				const pmremGenerator = new THREE.PMREMGenerator(this.renderer);
				this.scene.environment = pmremGenerator.fromScene(environment).texture;
				environment.dispose();

				this.container.appendChild(this.renderer.domElement);
			},

			initControls() {
				// 添加控制器
				this.controls = new OrbitControls(this.camera, this.renderer.domElement)
				//是否开启右键拖拽
				this.controls.enablePan = true;
				//是否可以缩放
				this.controls.enableZoom = true;
				//设置相机距离原点的最近距离
				this.controls.minDistance = 2;
				//设置相机距离原点的最远距离
				this.controls.maxDistance = 60;
				this.controls.addEventListener('change', this.render);
				this.controls.update();
			},

			initCamera() {
				// 定义正投影相机
				const width = this.container.clientWidth; //窗口宽度
				const height = this.container.clientHeight; //窗口高度
				let k = width / height; //窗口宽高比
				let s = 200; //三维场景显示范围控制系数，系数越大，显示的范围越大
				//创建相机对象
				//let camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
				this.camera = new THREE.PerspectiveCamera(45, width / height, 1, 100);
				this.camera.position.set(2, 2, 0); //设置相机位置
				this.camera.lookAt(this.scene.position); //设置相机方向(指向的场景对象)
			},

			initLight() {
				// 半球光
				const hemiLight = new THREE.HemisphereLight();
				hemiLight.intensity = 0.3
				this.scene.add(hemiLight);
				// 环境光
				const ambientLight = new THREE.AmbientLight(0xffffff, 1);
				this.scene.add(ambientLight);
				// 平行光
				const light = new THREE.DirectionalLight(0xffffff, 1);
				light.position.set(50, 50, 50);
				this.scene.add(light);
				// 点光源
				const pointLight = new THREE.PointLight(0xffffff, 3);
				this.scene.add(pointLight);
			},

			async loadGLTF(url) {
				this.progress = 0;
				try {
					const gltf = await new Promise((resolve, reject) => {
						new GLTFLoader().load(url,
							// 加载完成后回调
							gltf => {
								resolve(gltf);
							},
							// 加载进度回调
							xhr => {
								this.progress = Math.round((xhr.loaded / xhr.total) * 100);
								console.log(this.progress)
							},
							// 加载错误回调
							error => {
								reject(error);
							});
					});
					return gltf.scene;
				} catch (error) {
					console.error('加载模型错误：' + error);
					this.isLoading = false;
				}
			},

			initMaterial() {
				// 物理基准材质(PBR材质)
				const standardMaterial = new THREE.MeshStandardMaterial({
					color: 0xff0000,
					metalness: 1.0, //金属度属性
					roughness: 0.5, //表面粗糙度
				});
				this.wheels.add(standardMaterial)
				// 物理材质(PBR材质)
				const physicalMaterial = new THREE.MeshPhysicalMaterial({
					color: 0x00ffff,
					metalness: 0.9, //金属度
					roughness: 0.5, //粗糙度
					clearcoat: 1.0, //物体表面清漆层或者说透明涂层的厚度
					clearcoatRoughness: 0.1, //透明涂层表面的粗糙度
					transmission: 1.0, //玻璃材质透光率，
					ior: 1.5, //折射率
				});
				this.wheels.add(physicalMaterial)
				// 基础材质
				const basicMaterial = new THREE.MeshBasicMaterial({
					color: 0xff0000,
				});
				this.wheels.add(basicMaterial)
				// 高光材质(聚光)
				const phongMaterial = new THREE.MeshPhongMaterial({
					color: 0xff0000,
					shininess: 20,
					specular: 0x444444, //高光部分的颜色
				})
				this.wheels.add(phongMaterial)
				// 漫反射材质(散光)
				const lambertMaterial = new THREE.MeshLambertMaterial({
					color: 0xff0000,
				})
				this.wheels.add(lambertMaterial)
			},

			initModelMenu(obj) {
				const folder = this.gui.addFolder(obj.name);
				// 配置材质菜单
				if (obj.material instanceof THREE.MeshPhysicalMaterial) {
					folder.addColor({color: obj.material.color}, 'color').name("颜色");
					folder.add(obj.material, 'metalness', 0, 1).name("金属度");
					folder.add(obj.material, 'roughness', 0, 1).name("粗糙度");
					folder.add(obj.material, 'transmission', 0, 1).name("透光率");
					folder.add(obj.material, 'ior', 0, 3).name("折射率");
				} else if (obj.material instanceof THREE.MeshStandardMaterial) {
					folder.addColor({color: obj.material.color,}, 'color').name("颜色");
				}
				folder.close(); //关闭菜单
			},

			//执行渲染操作   指定场景、相机作为参数
			render() {
				this.renderer.render(this.scene, this.camera);
			},

			animate() {
				this.stats.update();
				this.controls && this.controls.update();
				this.render();
				requestAnimationFrame(this.animate);
			},

			setCenter(theObject) {
				let root = theObject; //this.scene;
				let box = new THREE.Box3().setFromObject(root);
				let temp = new THREE.Vector3();
				let center = box.getCenter(new THREE.Vector3());
				let size = box.getSize(new THREE.Vector3());
				// console.log('old center,size:', center, size);
				let maxAxis = Math.max(size.x, size.y, size.z);
				root.scale.multiplyScalar(1 / maxAxis); //模型显示大小可调整参数 5 
				box.setFromObject(root);
				center = box.getCenter(new THREE.Vector3());
				size = box.getSize(new THREE.Vector3());
				// center = new THREE.Vector3()
				root.position.sub(center); // 位置居中
				// console.log('new center,size:', center, size);
			},

			onWindowResize() {
				const width = this.container.clientWidth; //canvas画布宽度
				const height = this.container.clientHeight; //canvas画布高度
				// 1. WebGL渲染器渲染的Cnavas画布尺寸更新
				renderer.setSize(width, height);
				// 2.1.更新相机参数
				// const k = width / height; //canvas画布宽高比
				// camera.left = -s*k;
				// camera.right = s*k;
				camera.aspect = width / height;
				// 2.2.相机的left, right, top, bottom属性变化了，通知threejs系统
				camera.updateProjectionMatrix();
			},
		},

		beforeDestroy() {
			// 移除绑定的事件监听
			window.removeEventListener('resize', this.onWindowResize);
		}

	}
</script>

<style>
	.webgl-content * {
		border: 0;
		margin: 0;
		padding: 0;
	}

	.webgl-content {
		position: absolute;
		top: 50%;
		left: 50%;
		width: 100%;
		height: 100%;
		-webkit-transform: translate(-50%, -50%);
		transform: translate(-50%, -50%);
	}

	.progress {
		position: absolute;
		bottom: 10px;
		left: 10%;
		width: 80%;
		height: 18px;
		z-index: 10000;
		background-color: #c5c5c5;
		border: 1px solid #c5c5c5;
		border-radius: 5px;
	}

	.progress-full {
		background-color: #6c6c6c;
		float: left;
		/* width: 34%; */
		height: 18px;
		display: inline-block;
	}
</style>